# -*- coding:utf-8 -*-
# --author： jingfeng 
# time: 2019/2/12


from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait # 等待元素加载的
from selenium.webdriver.common.action_chains import ActionChains  #拖拽
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException, NoSuchElementException
from selenium.webdriver.common.by import By
from PIL import Image
import requests
import time
import re
import random
from io import BytesIO
from bs4 import BeautifulSoup
from lxml import etree




class LoginBzhan(object):
    def __init__(self):
        self.browser = webdriver.Chrome()
        self.wait = WebDriverWait(self.browser,30)

    def get_image(self, background_images):
        """
        获得原图，残图
        :param html: 
        :return: 
        """

        location_list = []
        for background_image in background_images:
            location = {}
            print(background_image)
            result = re.findall(
                'background-image: url\("(.*?)"\); background-position: (.*?)px (.*?)px;',
                background_image)
            print(result)
            location['x'] = int(result[0][1])
            location['y'] = int(result[0][2])

            image_url = result[0][0]
            location_list.append(location)

        print('==================================')
        image_url = image_url.replace('webp', 'jpg')  # 替换后缀名
        # '替换https://static.geetest.com/pictures/gt/c144b9841/c144b9841.webp'
        image_result = requests.get(image_url).content

        # 内存当磁盘
        image_file = BytesIO(image_result)  # 是一张无序的图片
        image = self.merge_image(image_file, location_list)

        return image


    def merge_image(self, image_file, location_list):
        """
         拼接图片
        :param image_file:    无序的图片
        :param location_list: 位置
        :return:
        """
        im = Image.open(image_file)
        im.save('code.jpg')
        new_im = Image.new('RGB', (260, 116))
        # 把无序的图片 切成52张小图片
        im_list_upper = []
        im_list_down = []
        # print(location_list)
        for location in location_list:
            # print(location['y'])
            if location['y'] == -58:  # 上半边
                im_list_upper.append(im.crop(
                    (abs(location['x']), 58, abs(location['x']) + 10, 116)))
            if location['y'] == 0:  # 下半边
                im_list_down.append(im.crop(
                    (abs(location['x']), 0, abs(location['x']) + 10, 58)))

        x_offset = 0
        for im in im_list_upper:
            new_im.paste(im, (x_offset, 0))  # 把小图片放到 新的空白图片上
            x_offset += im.size[0]

        x_offset = 0
        for im in im_list_down:
            new_im.paste(im, (x_offset, 58))
            x_offset += im.size[0]
      #  new_im.show()
        return new_im


    def get_track(self,distance):
        '''
        拿到移动轨迹，模仿人的滑动行为，先匀加速后匀减速
        匀变速运动基本公式：
        ①v=v0+at
        ②s=v0t+(1/2)at²
        ③v²-v0²=2as

        :param distance: 需要移动的距离
        :return: 存放每0.2秒移动的距离
        '''
        # 初速度
        v = 0
        # 单位时间为0.2s来统计轨迹，轨迹即0.2内的位移
        t = 0.2
        # 位移/轨迹列表，列表内的一个元素代表0.2s的位移
        tracks = []
        # 当前的位移
        current = 0
        # 到达mid值开始减速
        mid = distance * 7 / 8

        distance += 10  # 先滑过一点，最后再反着滑动回来
        # a = random.randint(1,3)
        while current < distance:
            if current < mid:
                # 加速度越小，单位时间的位移越小,模拟的轨迹就越多越详细
                a = random.randint(2, 4)  # 加速运动
            else:
                a = -random.randint(3, 5)  # 减速运动

            # 初速度
            v0 = v
            # 0.2秒时间内的位移
            s = v0 * t + 0.5 * a * (t ** 2)
            # 当前的位置
            current += s
            # 添加到轨迹列表
            tracks.append(round(s))

            # 速度已经达到v,该速度作为下次的初速度
            v = v0 + a * t

        # 反着滑动到大概准确位置
        for i in range(4):
            tracks.append(-random.randint(2, 3))
        for i in range(4):
            tracks.append(-random.randint(1, 3))
        return tracks


    def get_distance(self,image1, image2):
        '''
          拿到滑动验证码需要移动的距离
          :param image1:没有缺口的图片对象
          :param image2:带缺口的图片对象
          :return:需要移动的距离
          '''
        # print('size', image1.size)

        threshold = 50
        for i in range(0, image1.size[0]):  # 260
            for j in range(0, image1.size[1]):  # 160
                pixel1 = image1.getpixel((i, j))
                pixel2 = image2.getpixel((i, j))
                res_R = abs(pixel1[0] - pixel2[0])  # 计算RGB差
                res_G = abs(pixel1[1] - pixel2[1])  # 计算RGB差
                res_B = abs(pixel1[2] - pixel2[2])  # 计算RGB差
                if res_R > threshold and res_G > threshold and res_B > threshold:
                    return i  # 需要移动的距离

    def login(self):
        self.browser.get('https://passport.bilibili.com/login')
        username = self.wait.until(
            EC.presence_of_element_located((By.ID,'login-username')))
        password = self.wait.until(
            EC.presence_of_element_located((By.ID, 'login-passwd')))


        btn_login = self.browser.find_element_by_xpath('//a[@class="btn btn-login"]')

        username.send_keys('17635395714')
        password.send_keys('czp0927')
        btn_login.click()

        # 等待滑动按钮加载完成
        time.sleep(6)
        selector = etree.HTML(self.browser.page_source)

        background_images1 = selector.xpath(
            '//div[@class="gt_cut_fullbg_slice"]/@style')
        background_images2 = selector.xpath(
            '//div[@class="gt_cut_bg_slice"]/@style')

        image1 = self.get_image(background_images1)
        image2 = self.get_image(background_images2)

        distance = self.get_distance(image1, image2)
        print(distance)

        track = self.get_track(distance)
        print(track)

       # track_list = get_track(l)
        print('第一步,点击滑动按钮')
        element = self.browser.find_element_by_xpath('//div[@class="gt_slider_knob gt_show"]')
        ActionChains(self.browser).click_and_hold(
            on_element=element).perform()  # 点击鼠标左键，按住不放
        time.sleep(1)
        print('第二步,拖动元素')
        for track in track:
            ActionChains(self.browser).move_by_offset(xoffset=track,
                                                yoffset=0).perform()  # 鼠标移动到距离当前位置（x,y）
            time.sleep(0.002)
        # if l>100:

        ActionChains(self.browser).move_by_offset(xoffset=-random.randint(2, 5),
                                            yoffset=0).perform()
        time.sleep(1)
        print('第三步,释放鼠标')
        ActionChains(self.browser).release(on_element=element).perform()
        time.sleep(20)
        print(self.browser.page_source)

    def __del__(self):
        self.browser.close()


if __name__ == '__main__':
    logins = LoginBzhan()
    logins.login()
